﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using EPiServer.DataAbstraction;
using EPiSugar.Configuration;
using EPiSugar.EntityAdapter;
using EPiSugar.Navigation;
using EPiSugar.Tests.EntityAdapter.Entities;
using EPiSugar.UnitTesting;
using NUnit.Framework;
using EPiServer.Core;
using NUnit.Framework.SyntaxHelpers;

namespace EPiSugar.Tests.EntityAdapter
{
    [TestFixture]
    public class EntitySystemTests : FakingEPiServerTests
    {
        [TestFixtureSetUp]
        public override void TestFixtureSetUp()
        {
            base.TestFixtureSetUp();

            
            TypeMappingCollection mappings = new TypeMappingCollection();
            PageTypeCollection types = new PageTypeCollection();

            AddMapping(mappings, types, Fakes.RootPageTypeID, typeof(Root));
            AddMapping(mappings, types, Fakes.WastebasketTypeID, typeof(Wastebasket));
            AddMapping(mappings, types, Fakes.StartPageTypeID, typeof(StartPage));
            AddMapping(mappings, types, Fakes.NormalPageTypeID, typeof(Page));

            EPiSugarSection section = new EPiSugarSection { TypeMappings = mappings };

            Current.Initialize(section, types, Fakes.CurrentPageProvider);
        }

        private void AddMapping(TypeMappingCollection mappings, PageTypeCollection types, int pageTypeID, Type entityType)
        {
            PageType pageType = CreateType(pageTypeID);
            types.Add(pageType);
            mappings.Add(new TypeMappingElement { EntityType = entityType.AssemblyQualifiedName, PageTypeID = pageTypeID });
        }

        private PageType CreateType(int pageTypeID)
        {
            PageType pageType = new PageType(pageTypeID, Guid.NewGuid(), "PageType" + pageTypeID, "", "/page" + pageTypeID + ".aspx", true, pageTypeID);
            pageType.Definitions.Add(new PageDefinition { Name = "MainIntro" });
            pageType.Definitions.Add(new PageDefinition { Name = "MainBody" });
            pageType.Definitions.Add(new PageDefinition { Name = "ReadMoreLink" });
            return pageType;
        }

        EntityContext<object> context;
            
        [SetUp]
        public void SetUp()
        {
            context = new EntityContext<object>();
        }

        [Test]
        public void CanMapRootPage_FromObjectContext()
        {
            Fakes.CurrentPageProvider.CurrentPage = PageReference.RootPage.Page();

            Assert.That(context.Current, Is.TypeOf(typeof(Root)));
        }

        [Test]
        public void CanMapWastebasket_FromObjectContext()
        {
            Fakes.CurrentPageProvider.CurrentPage = PageReference.WasteBasket.Page();

            Assert.That(context.Current, Is.TypeOf(typeof(Wastebasket)));
        }

        [Test]
        public void CanMapStartPage_FromObjectContext()
        {
            Fakes.CurrentPageProvider.CurrentPage = PageReference.StartPage.Page();

            Assert.That(context.Current, Is.TypeOf(typeof(StartPage)));
        }

        [Test]
        public void CanReadChildren_FromObjectContext()
        {
            IEnumerable<object> children = context.Children<object>(PageReference.StartPage);
            Assert.That(children.Count(), Is.EqualTo(3));
            foreach (object o in children)
            {
                Assert.That(o, Is.TypeOf(typeof(Page)));
            }
        }

        [Test]
        public void CanMapNormalPage_FromObjectContext()
        {
            Fakes.CurrentPageProvider.CurrentPage = PageReference.StartPage.Children().First();

            Assert.That(context.Current, Is.TypeOf(typeof(Page)));
        }

        [Test]
        public void CanBindTo_PageName()
        {
            PageData page = PageReference.StartPage.Page();
            Page entity = context.Get<Page>(PageReference.StartPage);
            Assert.That(entity.Name, Is.EqualTo(page.PageName));
        }

        [Test]
        public void CanBindTo_StartPublish()
        {
            PageData page = PageReference.StartPage.Page();
            Page entity = context.Get<Page>(PageReference.StartPage);
            Assert.That(entity.Published, Is.EqualTo(page.StartPublish));
        }

        [Test]
        public void CanBindTo_StopPublish()
        {
            PageData page = PageReference.StartPage.Page();
            Page entity = context.Get<Page>(PageReference.StartPage);
            Assert.That(entity.Expires, Is.EqualTo(page.StopPublish));
        }

        [Test]
        public void CanBind_Children()
        {
            Page entity = context.Get<Page>(PageReference.StartPage);
            Assert.That(entity.Children.Count, Is.EqualTo(3));
        }

        [Test]
        public void CanBindTo_AutoProperty()
        {
            PageReference link = PageReference.StartPage.Children().First().PageLink;
            Page entity = context.Get<Page>(link);

            Assert.That(entity.MainBody, Is.EqualTo(FakeStructureBuilder.DefaultBodyText));
        }

        [Test]
        public void CanBindTo_DefinedProperty()
        {
            PageReference link = PageReference.StartPage.Children().First().PageLink;
            Page entity = context.Get<Page>(link);

            Assert.That(entity.Summary, Is.EqualTo(FakeStructureBuilder.DefaultIntroText));
        }

        [Test]
        public void CanConvert_PageCollection_ToEntityCollection()
        {
            IEnumerable<Page> entities = PageReference.StartPage.Descendants().ToEntities<Page>();
            Assert.That(entities.Count(), Is.EqualTo(12));
        }

        [Test]
        public void CanConvert_Page_ToEntity()
        {
            Page entity = PageReference.StartPage.Page().ToEntity<Page>();
            Assert.That(entity is StartPage);
        }

        [Test]
        public void CanReference_AnotherPage()
        {
            PageData startPage = PageReference.StartPage.Page();
            PageData referencedPage = PageReference.StartPage.Children().First();
            startPage.Property["ReadMoreLink"] = new PropertyPageReference(referencedPage.PageLink);

            Page entity = startPage.ToEntity<Page>();
            Assert.That(entity.ReadMore.Name, Is.EqualTo(referencedPage.ToEntity<Page>().Name));
        }
    }
}
